﻿package frEngine.shader
{
    import __AS3__.vec.*;
    import baseEngine.core.*;
    import baseEngine.materials.*;
    import baseEngine.system.*;
    import flash.display3D.*;
    import flash.display3D.textures.*;
    import frEngine.*;
    import frEngine.core.*;
    import frEngine.event.*;
    import frEngine.manager.*;
    import frEngine.shader.filters.*;
    import frEngine.shader.filters.fragmentFilters.*;
    import frEngine.shader.filters.vertexFilters.*;
    import frEngine.shader.filters.vertexFilters.def.*;
    import frEngine.shader.registType.*;
    import frEngine.shader.registType.base.*;

    public class ShaderBase extends Material3D
    {
        public var materialParams:MaterialParams;
        public static var pro:Program3D;
        public static var cullFace:String;
        public static var depthWrite:Boolean;
        public static var depthCompare:String;
        public static var sourceFactor:String;
        public static var destFactor:String;
        public static var textures:Array = new Array(8);
        public static var buffers:Array = new Array(8);
        private static const defaultEmptyArray:Array = [];

        public function ShaderBase(param1:String, param2:VertexFilter = null, param3:FragmentFilter = null)
        {
            this.materialParams = new MaterialParams();
            super(param1);
            return;
        }// end function

        public function getParam(param1:String, param2:Boolean)
        {
            if (this.materialParams.program)
            {
                return this.materialParams.program.getParamByName(param1, param2);
            }
            return null;
        }// end function

        override public function clone() : Material3D
        {
            var _loc_1:* = new ShaderBase(this.name + "_clone");
            _loc_1.materialParams.cloneFrom(this.materialParams);
            return _loc_1;
        }// end function

        final public function hasPrepared(param1:Pivot3D, param2:FrSurface3D) : Boolean
        {
            if (!param2)
            {
                return false;
            }
            var _loc_3:Boolean = false;
            if (this.materialParams.needRebuild)
            {
                this.buildBytes();
            }
            var _loc_4:* = this.materialParams.program;
            if (this.materialParams.needRebuild)
            {
                _loc_3 = !this.materialParams.needRebuild && _loc_4 && _loc_4.instanceRegister.hasAssembler;
            }
            else if (_loc_4)
            {
                _loc_3 = _loc_4.instanceRegister.hasAssembler;
            }
            if (param2.needUpdate && param2.impUpload)
            {
                param2.contextEvent(Global3D.scene.context);
            }
            if (param2.targetInfo && param2.targetInfo.needReload)
            {
                param2.targetInfo.reload();
                return false;
            }
            _loc_3 = _loc_3 && !param2.needUpdate;
            return _loc_3;
        }// end function

        override public function draw(param1:Pivot3D, param2:Surface3D, param3:String, param4:String, param5:Boolean, param6:String, param7:String, param8:int = 0, param9:int = -1) : void
        {
            var _loc_13:int = 0;
            var _loc_14:int = 0;
            var _loc_20:MaxtrixParam = null;
            var _loc_21:ConstParamBase = null;
            var _loc_22:uint = 0;
            var _loc_25:Vector.<Number> = null;
            var _loc_28:FsParam = null;
            var _loc_29:Texture3D = null;
            var _loc_30:TextureBase = null;
            var _loc_31:int = 0;
            var _loc_32:VaParam = null;
            var _loc_33:uint = 0;
            var _loc_34:int = 0;
            var _loc_35:BufferVo = null;
            var _loc_36:VertexBuffer3D = null;
            var _loc_10:* = this.materialParams.program;
            if (!_loc_10)
            {
                return;
            }
            var _loc_11:* = FrSurface3D(param2);
            var _loc_12:* = param1.scene.context;
            _loc_13 = 0;
            var _loc_15:* = _loc_10.textures;
            _loc_14 = _loc_15.length;
            var _loc_16:* = ShaderBase.textures;
            while (_loc_13 < _loc_14)
            {
                
                _loc_28 = _loc_15[_loc_13];
                _loc_29 = _loc_28.value;
                if (!_loc_29)
                {
                    _loc_13 = 0;
                    break;
                }
                _loc_30 = _loc_29.texture;
                if (!_loc_30)
                {
                    _loc_13 = 0;
                    if (_loc_29.loadFlag == 0 && _loc_29.targetInfo)
                    {
                        _loc_29.load();
                    }
                    break;
                }
                _loc_31 = _loc_28.index;
                if (_loc_16[_loc_31] != _loc_30)
                {
                    _loc_12.setTextureAt(_loc_31, _loc_30);
                    _loc_16[_loc_31] = _loc_30;
                }
                _loc_13++;
            }
            var _loc_17:* = Global3D.usedSamples;
            while (_loc_13 < _loc_17)
            {
                
                _loc_12.setTextureAt(_loc_13, null);
                _loc_16[_loc_13] = null;
                _loc_13++;
            }
            if (_loc_14 > 0 && _loc_13 == 0)
            {
                Global3D.usedSamples = 0;
                return;
            }
            Global3D.usedSamples = _loc_14;
            if (ShaderBase.pro != _loc_10.program)
            {
                _loc_12.setProgram(_loc_10.program);
                ShaderBase.pro = _loc_10.program;
            }
            if (ShaderBase.cullFace != param4)
            {
                _loc_12.setCulling(param4);
                ShaderBase.cullFace = param4;
            }
            if (ShaderBase.depthWrite != param5 || ShaderBase.depthCompare != param3)
            {
                _loc_12.setDepthTest(param5, param3);
                ShaderBase.depthWrite = param5;
                ShaderBase.depthCompare = param3;
            }
            if (ShaderBase.sourceFactor != param6 || ShaderBase.destFactor != param7)
            {
                _loc_12.setBlendFactors(param6, param7);
                ShaderBase.sourceFactor = param6;
                ShaderBase.destFactor = param7;
            }
            _loc_13 = 0;
            var _loc_18:* = _loc_10.VaParamsList;
            _loc_14 = _loc_18.length;
            var _loc_19:* = ShaderBase.buffers;
            while (_loc_13 < _loc_14)
            {
                
                _loc_32 = _loc_18[_loc_13];
                _loc_33 = _loc_32.vertexNameId;
                _loc_34 = _loc_32.index;
                _loc_35 = _loc_11.bufferVoMap[_loc_33];
                if (!_loc_35)
                {
                    return;
                }
                _loc_36 = _loc_35.buffer.vertexBuffer;
                if (_loc_19[_loc_34] != _loc_36)
                {
                    _loc_12.setVertexBufferAt(_loc_34, _loc_36, _loc_35.offset, _loc_35.format);
                    _loc_19[_loc_34] = _loc_36;
                }
                _loc_13++;
            }
            while (_loc_13 < Global3D.usedBuffers)
            {
                
                _loc_12.setVertexBufferAt(_loc_13, null);
                _loc_19[_loc_13] = null;
                _loc_13++;
            }
            Global3D.usedBuffers = _loc_14;
            var _loc_23:* = _loc_10.VcParamsConstList;
            _loc_14 = _loc_23.length;
            var _loc_24:* = Context3DProgramType.VERTEX;
            _loc_13 = 0;
            while (_loc_13 < _loc_14)
            {
                
                _loc_21 = _loc_23[_loc_13];
                _loc_25 = _loc_21.value;
                _loc_22 = _loc_25.length >> 2;
                _loc_12.setProgramConstantsFromVector(_loc_24, _loc_21.index, _loc_25, _loc_22);
                _loc_13++;
            }
            var _loc_26:* = _loc_10.FcParamsConstList;
            _loc_14 = _loc_26.length;
            _loc_24 = Context3DProgramType.FRAGMENT;
            _loc_13 = 0;
            while (_loc_13 < _loc_14)
            {
                
                _loc_21 = _loc_26[_loc_13];
                _loc_25 = _loc_21.value;
                _loc_22 = _loc_25.length >> 2;
                _loc_12.setProgramConstantsFromVector(_loc_24, _loc_21.index, _loc_25, _loc_22);
                _loc_13++;
            }
            var _loc_27:* = _loc_10.paramsMaxtrixList;
            _loc_13 = 0;
            _loc_14 = _loc_27.length;
            while (_loc_13 < _loc_14)
            {
                
                _loc_20 = _loc_27[_loc_13];
                _loc_12.setProgramConstantsFromMatrix(_loc_20.type, _loc_20.index, _loc_20.value, true);
                _loc_13++;
            }
            _loc_12.drawTriangles(_loc_11.indexBufferFr.indexBuffer, param8, param9);
            var _loc_37:* = Global3D;
            var _loc_38:* = Global3D.drawCalls3d + 1;
            _loc_37.drawCalls3d = _loc_38;
            return;
        }// end function

        override public function dispose() : void
        {
            this.materialParams.dispose();
            FrEventDispatcher.instance.removeAllProxyEventListener(this);
            return;
        }// end function

        public function buildBytes() : Boolean
        {
            var _loc_5:int = 0;
            var _loc_6:int = 0;
            var _loc_7:FilterBase = null;
            var _loc_12:Program3dRegisterInstance = null;
            var _loc_13:String = null;
            if (!this.materialParams.needRebuild || !this.materialParams.vertexFilter || !this.materialParams.fragmentFilter)
            {
                return false;
            }
            if (this.materialParams.program)
            {
                this.materialParams.program.dispose();
                this.materialParams.program = null;
            }
            var _loc_1:* = this.materialParams.fragmentFilter.programeId;
            if (_loc_1 == null)
            {
                return false;
            }
            var _loc_2:* = this.materialParams.skinNum;
            var _loc_3:* = this.materialParams.vertexFilter.programeId;
            if (!_loc_3)
            {
                return false;
            }
            _loc_3 = _loc_3 + _loc_2;
            var _loc_4:Boolean = true;
            var _loc_8:* = this.materialParams.filterList;
            _loc_5 = _loc_8.length;
            _loc_8.sortOn("priority", Array.NUMERIC);
            _loc_4 = this.materialParams.uvRepeat;
            var _loc_9:Array = [_loc_3, _loc_1];
            _loc_6 = 0;
            while (_loc_6 < _loc_5)
            {
                
                _loc_7 = _loc_8[_loc_6];
                _loc_13 = _loc_7.programeId;
                if (!_loc_13)
                {
                    return false;
                }
                _loc_9.push(_loc_13);
                _loc_6++;
            }
            var _loc_10:* = _loc_9.join(",");
            var _loc_11:* = Program3dManager.instance.hasRegisterProgram3D(_loc_10, _loc_4);
            if (!_loc_11)
            {
                _loc_12 = createAndRegister(_loc_10, _loc_2, this.materialParams.vertexFilter, this.materialParams.fragmentFilter, _loc_8, _loc_4);
                this.materialParams.program = new FrProgram3D(_loc_4, _loc_10, _loc_12);
            }
            else
            {
                _loc_12 = Program3dManager.instance.getProgram3DInstance(_loc_10, _loc_4);
                this.materialParams.program = new FrProgram3D(_loc_4, _loc_10, _loc_12);
                this.setRegisterParams(_loc_12, _loc_8);
            }
            FrEventDispatcher.instance.proxyDispatchEvent(this, Engine3dEventName.MATERIAL_REBUILDER);
            this.materialParams.needRebuild = false;
            return true;
        }// end function

        private function setRegisterParams(param1:Program3dRegisterInstance, param2:Array) : void
        {
            var _loc_5:FilterBase = null;
            this.materialParams.vertexFilter.setRegisterParams(param1);
            this.materialParams.fragmentFilter.setRegisterParams(param1);
            var _loc_3:int = 0;
            var _loc_4:* = param2.length;
            _loc_3 = 0;
            while (_loc_3 < _loc_4)
            {
                
                _loc_5 = param2[_loc_3];
                _loc_5.setRegisterParams(param1);
                _loc_3++;
            }
            return;
        }// end function

        public function update() : void
        {
            return;
        }// end function

        public function clear() : void
        {
            return;
        }// end function

        private static function createAndRegister(param1:String, param2:int, param3:VertexFilter, param4:FragmentFilter, param5:Array, param6:Boolean) : Program3dRegisterInstance
        {
            var _loc_12:FilterBase = null;
            var _loc_7:* = new Program3dRegisterInstance(param1);
            var _loc_8:String = "";
            var _loc_9:String = "";
            _loc_8 = param3.createVertexCode(_loc_7, param2);
            _loc_8 = _loc_8 + param4.createVertexCode(_loc_7, param2);
            var _loc_10:int = 0;
            var _loc_11:* = param5.length;
            _loc_10 = 0;
            while (_loc_10 < _loc_11)
            {
                
                _loc_12 = param5[_loc_10];
                _loc_8 = _loc_8 + _loc_12.createVertexCode(_loc_7, param2);
                _loc_10++;
            }
            _loc_8 = _loc_8 + completeCode(_loc_7);
            _loc_9 = param4.preCreateFragmentUvCoord(_loc_7);
            _loc_9 = _loc_9 + param3.preCreateFragmentUvCoord(_loc_7);
            _loc_9 = _loc_9 + param4.createFragmentUvCoord(_loc_7);
            _loc_9 = _loc_9 + param3.createFragmentUvCoord(_loc_7);
            _loc_10 = 0;
            while (_loc_10 < _loc_11)
            {
                
                _loc_12 = param5[_loc_10];
                _loc_9 = _loc_9 + _loc_12.createFragmentUvCoord(_loc_7);
                _loc_10++;
            }
            _loc_9 = _loc_9 + param4.createFragmentColor(_loc_7, param6);
            _loc_9 = _loc_9 + param3.createFragmentColor(_loc_7, param6);
            _loc_10 = 0;
            while (_loc_10 < _loc_11)
            {
                
                _loc_12 = param5[_loc_10];
                _loc_9 = _loc_9 + _loc_12.createFragmentColor(_loc_7, param6);
                _loc_10++;
            }
            _loc_7.upload(Global3D.scene, _loc_8, _loc_9, param6);
            Program3dManager.instance.registerPrograme(_loc_7, param6);
            return _loc_7;
        }// end function

        private static function completeCode(param1:Program3dRegisterInstance) : String
        {
            var _loc_2:Array = [];
            var _loc_3:String = "";
            var _loc_4:* = param1.getParamByName(FilterName.V_GloblePos, true);
            var _loc_5:* = param1.getParamByName(FilterName.V_Screen, true);
            var _loc_6:* = param1.OpType;
            if (_loc_6 == ECalculateOpType.None)
            {
            }
            else if (_loc_6 == ECalculateOpType.Proj)
            {
                if (_loc_4)
                {
                    _loc_3 = _loc_3 + "mov,{V_GloblePos},{output}\n";
                }
                _loc_2.push(new ToBuilderInfo("vm1", FilterName.proj, true, 4));
                _loc_3 = _loc_3 + "m44,{output},{output},vm1\n";
            }
            else if (_loc_6 == ECalculateOpType.ViewProj)
            {
                if (_loc_4)
                {
                    _loc_3 = _loc_3 + "mov,{V_GloblePos},{output}\n";
                }
                _loc_3 = _loc_3 + "m44,{output},{output},{viewProj}\n";
            }
            else if (_loc_6 == ECalculateOpType.WorldViewProj)
            {
                if (_loc_4)
                {
                    _loc_3 = _loc_3 + "mov,{V_GloblePos},{output}\n";
                }
                _loc_2.push(new ToBuilderInfo("vm1", FilterName.worldViewProj, true, 4));
                _loc_3 = _loc_3 + "m44,{output},{output},vm1\n";
            }
            else if (_loc_6 == ECalculateOpType.World_And_ViewProj)
            {
                _loc_2.push(new ToBuilderInfo("vm1", FilterName.global, true, 4));
                _loc_3 = _loc_3 + "m44,{output},{output},vm1\n";
                if (_loc_4)
                {
                    _loc_3 = _loc_3 + "mov,{V_GloblePos},{output}\n";
                }
                _loc_3 = _loc_3 + "m44,{output},{output},{viewProj}\n";
            }
            if (_loc_5)
            {
                _loc_3 = _loc_3 + "div,{V_Screen},{output},{output}.w\n";
            }
            _loc_3 = _loc_3 + "mov,op,{output}\n";
            _loc_3 = param1.toBuild(_loc_3, _loc_2);
            return _loc_3;
        }// end function

    }
}
